import datetime
import logging
import tabulate

from coin.exchange.bitflyer_v1.kr_rest.currency import BitflyerCurrency
from coin.strategy.accounting.pnl_balance_printer.pnl_balance_printer import FuturesPnlBalancePrinter


def calculate_unrealized_pnl(pos, avg_price, mid_price):
  if pos == 0:
    return 0
  return pos * (mid_price - avg_price)


class BitflyerFuturesPnlBalancePrinter(FuturesPnlBalancePrinter):
  def __init__(self, products, bookmap, reserve_map, pos_bias_map=None, logger=None):
    self._currency = BitflyerCurrency.FromStrCurrency('JPY')
    self._pos_bias_map = pos_bias_map or {}
    super().__init__(products,
                     bookmap,
                     reserve_map,
                     logger=(logger or logging.getLogger('BitflyerFuturesPnlBalancePrinter')))

  def _get_pos(self, product):
    book = self._bookmap.get_book(product)
    if book is None or not book.has_ask() or not book.has_bid():
      return None, None

    pos = self._og.get_position(product)
    average_entry_price = self._og.get_average_entry_price(product)

    midp = (book.ask0().price + book.bid0().price) / 2.
    unrealized_pnl = calculate_unrealized_pnl(pos, average_entry_price, midp)

    if product in self._pos_bias_map and self._pos_bias_map[product] != 0:
      pos_bias, pos_bias_price = self._pos_bias_map[product]
      if pos_bias_price is None:
        pos_bias_price = 0
      unrealized_pnl_from_bias = calculate_unrealized_pnl(pos_bias, pos_bias_price, midp)
      return pos + pos_bias, unrealized_pnl + unrealized_pnl_from_bias
    else:
      return pos, unrealized_pnl

  def print_pnl_balance(self):
    if self._og is None or not self._og.is_ready():
      return

    table = []
    total_upnl = 0.
    for product in self._products:
      pos, unrealized_pnl = self._get_pos(product)
      total_upnl += (unrealized_pnl or 0.)
      table.append(['*', str(product), pos, unrealized_pnl])

    balance = self._og.get_balance(self._currency)

    table.append(['*', self._currency, None, balance])
    table.append(['*', 'Total', None, total_upnl + balance])

    pos_bal_table_str = tabulate.tabulate(table,
                                          headers=['*', 'Product', 'Position', 'Value'],
                                          floatfmt='.3f')
    self._logger.info('----- Position and balance:\n* %s\n%s',
                      str(datetime.datetime.now()),
                      pos_bal_table_str)
